package co.gov.medellin.ssti.sub.model.dao.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import co.gov.medellin.ssti.sub.common.util.FiltrosReportesUtil;
import co.gov.medellin.ssti.sub.model.dao.IReporteTotalComunaDAO;
import co.gov.medellin.ssti.sub.model.vo.CondicionConsultaVO;
import co.gov.medellin.ssti.sub.model.vo.ReportComunaVO;
import co.gov.medellin.ssti.sub.model.vo.ReporteTotalComunaVO;
import co.gov.medellin.ssti.sub.model.vo.VflexVO;
import co.gov.medellin.ssti.sub.model.service.ReporteTotalComunaService;
import co.gov.medellin.ssti.sub.service.VflexService;

public class ReporteTotalComunaDAOImpl extends BaseDAOImpl implements
		IReporteTotalComunaDAO {
	/*
	 * private static Logger logger = Logger
	 * .getLogger(ReporteTotalComunaDAOImpl.class);
	 */

	public ReporteTotalComunaDAOImpl(Connection con) {
		super(con);
	}

	@SuppressWarnings("unchecked")
	public Collection<ReportComunaVO> findBeneficiosBeneficiariosComuna(
			ReporteTotalComunaVO criteria,
			Collection<CondicionConsultaVO> filtros) throws SQLException {
		PreparedStatement pstmt = null;
		ResultSet rst = null;

		// parte adicional de la consulta (criterios de busqueda.)
		StringBuffer queryVars = new StringBuffer();
		List<Object> parametersQueryVars = new ArrayList<Object>();
		StringBuffer sbQueryVars = new StringBuffer();
		List<Object> parametersSbQueryVars = new ArrayList<Object>();

		if ((Object) criteria.getCodeZona() != null) {
			queryVars.append(" AND (ben.vfl_codigo_zona = ? ");
			sbQueryVars.append(" AND (ben_.vfl_codigo_zona = ? ");
			parametersQueryVars.add(criteria.getCodeZona());
			parametersSbQueryVars.add(criteria.getCodeZona());
			// si tiene elegida una zona, pero no tiene elegida una comuna..
			if ((Object) criteria.getCodeComuna() == null) {
				VflexService vflexService = new VflexService();
				Collection<VflexVO> comunas = vflexService.findVflex("COMUNA",
						Long.toString(criteria.getCodeZona().longValue()));
				Iterator<VflexVO> it = comunas.iterator();
				while (it.hasNext()) {
					VflexVO vflexVO = (VflexVO) it.next();
					// logger.debug("vflexvo.code:" + vflexVO.getCode());
					queryVars.append(" OR ben.vfl_codigo_comuna = ? ");
					parametersQueryVars.add(vflexVO.getCode());
					sbQueryVars.append(" OR ben_.vfl_codigo_comuna = ? ");
					parametersSbQueryVars.add(vflexVO.getCode());
				}
			}
			queryVars.append(" ) ");
			sbQueryVars.append(" ) ");
		}

		if ((Object) criteria.getCodeComuna() != null) {
			queryVars.append(" AND comuna.CODIGO = ? ");
			sbQueryVars.append(" AND comuna_.CODIGO = ? ");
			parametersQueryVars.add(criteria.getCodeComuna());
			parametersSbQueryVars.add(criteria.getCodeComuna());
		}
		if ((Object) criteria.getCodeSubprograma() != null) {
			queryVars.append(" AND subpro.CODIGO = ? ");
			sbQueryVars.append(" AND subpro_.CODIGO = ? ");
			parametersQueryVars.add(criteria.getCodeSubprograma());
			parametersSbQueryVars.add(criteria.getCodeSubprograma());
		}
		if ((Object) criteria.getCodePrograma() != null) {
			queryVars.append(" AND prog.CODIGO = ? ");
			sbQueryVars.append(" AND prog_.CODIGO = ? ");
			parametersQueryVars.add(criteria.getCodePrograma());
			parametersSbQueryVars.add(criteria.getCodePrograma());
		}
		if ((Object) criteria.getDesde() != null
				&& (Object) criteria.getHasta() != null) {
			queryVars
					.append(" AND beneotor.FECHA_BENEFICIO BETWEEN TO_DATE(?,'dd/mm/rrrr') AND TO_DATE(?,'dd/mm/rrrr') ");
			sbQueryVars
					.append(" AND beneotor_.FECHA_BENEFICIO BETWEEN TO_DATE(?,'dd/mm/rrrr') AND TO_DATE(?,'dd/mm/rrrr') ");
			parametersQueryVars.add(criteria.getDesde());
			parametersSbQueryVars.add(criteria.getDesde());
			parametersQueryVars.add(criteria.getHasta());
			parametersSbQueryVars.add(criteria.getHasta());
		}
		if ((Object) criteria.getDesde() != null
				&& (Object) criteria.getHasta() == null) {
			queryVars
					.append(" AND beneotor.FECHA_BENEFICIO >= TO_DATE(?,'dd/mm/rrrr') ");
			sbQueryVars
					.append(" AND beneotor_.FECHA_BENEFICIO >= TO_DATE(?,'dd/mm/rrrr')");
			parametersQueryVars.add(criteria.getDesde());
			parametersSbQueryVars.add(criteria.getDesde());
		}
		if ((Object) criteria.getDesde() == null
				&& (Object) criteria.getHasta() != null) {
			queryVars
					.append(" AND beneotor.FECHA_BENEFICIO <= TO_DATE(?,'dd/mm/rrrr') ");
			sbQueryVars
					.append(" AND beneotor_.FECHA_BENEFICIO <= TO_DATE(?,'dd/mm/rrrr') ");
			parametersQueryVars.add(criteria.getHasta());
			parametersSbQueryVars.add(criteria.getHasta());
		}

		Object[] ret = buildQueryFiltros(filtros);
		String queryFiltVars = (String) ret[0];
		List<Object> queryFiltParams = (List<Object>) ret[1];
		String sbQueryFiltVars = (String) ret[2];
		List<Object> sbQueryFiltParams = (List<Object>) ret[3];

		String query = "SELECT COUNT(DISTINCT beneotor.BEN_CODIGO) contbeneficiario, COUNT(beneotor.CODIGO) contbeneficio, "
				+ " SUM(beneotor.VALOR_BENEFICIO) valor, comuna.NOMBRE nomcomuna, prog.NOMBRE nompro, subpro.NOMBRE nomsubpro "

				// subquery
				+ " , (SELECT COUNT(DISTINCT ben_.codigo) FROM TCS_BEN_AREA subarea_ JOIN TCS_BEN_SUBPROGRAMA subpro_ ON subarea_.codigo = subpro_.area_codigo JOIN TCS_BEN_BENEFICIO_OTORGADO beneotor_ ON beneotor_.sbpr_codigo = subpro_.codigo JOIN TCS_BEN_BENEFICIARIO ben_ ON beneotor_.ben_codigo = ben_.codigo JOIN TCS_BEN_PROGRAMA prog_ ON subpro_.prg_codigo = prog_.codigo JOIN TCS_BEN_AREA area_ ON area_.codigo = subarea_.area_codigo JOIN PAOYER.TCS_VALOR_FLEXIBLE comuna_ ON ben_.vfl_codigo_comuna = comuna_.codigo WHERE prog_.vigencia='A' and subpro_.vigencia='A' "
				+ sbQueryVars.toString()
				+ sbQueryFiltVars
				+ " ) AS TOTAL_BENEFICIARIOS "

				+ ", area.NOMBRE nombre_secretaria "
				+ " FROM TCS_BEN_AREA subarea "
				+ " JOIN TCS_BEN_SUBPROGRAMA subpro"
				+ " ON subarea.codigo = subpro.area_codigo "
				+ " JOIN TCS_BEN_BENEFICIO_OTORGADO beneotor "
				+ " ON beneotor.sbpr_codigo = subpro.codigo "
				+ " JOIN TCS_BEN_BENEFICIARIO ben "
				+ " ON beneotor.ben_codigo = ben.codigo "
				+ " JOIN TCS_BEN_PROGRAMA prog "
				+ " ON subpro.prg_codigo = prog.codigo "
				+ " JOIN TCS_BEN_AREA area "
				+ " ON area.codigo = subarea.area_codigo "
				+ " JOIN PAOYER.TCS_VALOR_FLEXIBLE comuna "
				+ " ON ben.vfl_codigo_comuna = comuna.codigo "
				+ " WHERE prog.vigencia='A' and subpro.vigencia='A' ";

		query += queryVars.toString();
		query += queryFiltVars;
		if (criteria.getTipoReporte().equals(
				ReporteTotalComunaService.TIPO_REPORTE_1)) {
			query += " GROUP BY area.nombre, comuna.NOMBRE, prog.NOMBRE,subpro.NOMBRE ";
			query += " ORDER BY area.nombre, comuna.NOMBRE, prog.NOMBRE,subpro.NOMBRE ";
		} else if (criteria.getTipoReporte().equals(
				ReporteTotalComunaService.TIPO_REPORTE_2)) {
			query += " GROUP BY comuna.NOMBRE, area.nombre, prog.NOMBRE, subpro.NOMBRE ";
			query += " ORDER BY comuna.NOMBRE, area.nombre, prog.NOMBRE, subpro.NOMBRE ";
		}

		ArrayList<ReportComunaVO> lbeneotor = new ArrayList<ReportComunaVO>();

		// Se crea una lista, con los parametros en el orden que van en la
		// consulta, para agregar los parametros del
		// PreparedStatement usando el metodo setQueryParameters de BaseDAO
		List<Object> parameters = new ArrayList<Object>();
		parameters.addAll(parametersSbQueryVars);
		parameters.addAll(sbQueryFiltParams);
		parameters.addAll(parametersQueryVars);
		parameters.addAll(queryFiltParams);

		/*
		 * logger.info(query); Iterator it = parameters.iterator();
		 * while(it.hasNext()){ Object obj = it.next();
		 * System.out.println("param: " + obj.toString()); }
		 */
		try {
			pstmt = conn.prepareStatement(query);
			pstmt = setQueryParameters(pstmt, parameters);
			rst = pstmt.executeQuery();

			ReportComunaVO objbeneficios = null;
			long totalvalor = 0;
			long totalben = 0; // total beneficios
			long totalber = 0; // total beneficiarios
			int firstRow = 0;
			while (rst.next()) {
				objbeneficios = new ReportComunaVO();
				objbeneficios.setNombrePrograma(rst.getString("nompro"));
				objbeneficios.setNombreSubprograma(rst.getString("nomsubpro"));
				objbeneficios.setNombreComuna(rst.getString("nomcomuna"));
				objbeneficios.setContben(rst.getInt("contbeneficio"));
				objbeneficios.setContber(rst.getInt("contbeneficiario"));
				objbeneficios.setValor(rst.getLong("valor"));
				objbeneficios.setNombreSecretaria(rst
						.getString("nombre_secretaria"));
				totalvalor += rst.getLong("valor");
				totalben += rst.getLong("contbeneficio");
				// totalber += rst.getLong("contbeneficiario");

				if (firstRow == 0) {
					totalber = rst.getLong("TOTAL_BENEFICIARIOS");
					firstRow++;
				}
				lbeneotor.add(objbeneficios);
				objbeneficios = null;
			}
			if (lbeneotor.size() > 0) {
				objbeneficios = new ReportComunaVO();
				objbeneficios.setNombreComuna("VALOR TOTAL");
				objbeneficios.setContben(totalben);
				objbeneficios.setContber(totalber);
				objbeneficios.setValor(totalvalor);
				lbeneotor.add(objbeneficios);
				objbeneficios = null;
			}
		} finally {
			close(rst, pstmt);
		}
		return lbeneotor;
	}

	public ReporteTotalComunaVO findFilters(ReporteTotalComunaVO objRtcVO)
			throws SQLException {
		PreparedStatement pstmt = null;
		ResultSet rst = null;

		String strQuery = null;

		if (objRtcVO.getCodeComuna() != null) {
			strQuery = "SELECT NOMBRE FROM PAOYER.TCS_VALOR_FLEXIBLE "
					+ " WHERE CODIGO = ? ";
			try {
				pstmt = conn.prepareStatement(strQuery);
				pstmt.setLong(1, objRtcVO.getCodeComuna().longValue());
				rst = pstmt.executeQuery();
				if (rst.next()) {
					objRtcVO.setNombreComuna(rst.getString("NOMBRE"));
				}
			} finally {
				close(rst, pstmt);
			}
		}
		if (objRtcVO.getCodePrograma() != null) {
			strQuery = "SELECT NOMBRE FROM TCS_BEN_PROGRAMA "
					+ " WHERE CODIGO = ? ";
			try {
				pstmt = conn.prepareStatement(strQuery);
				pstmt.setLong(1, objRtcVO.getCodePrograma().longValue());
				rst = pstmt.executeQuery();
				if (rst.next()) {
					objRtcVO.setNombrePrograma(rst.getString("NOMBRE"));
				}
			} finally {
				close(rst, pstmt);
			}
		}
		if (objRtcVO.getCodeSubprograma() != null) {
			strQuery = "SELECT NOMBRE FROM TCS_BEN_SUBPROGRAMA "
					+ " WHERE CODIGO = ? ";
			try {
				pstmt = conn.prepareStatement(strQuery);
				pstmt.setLong(1, objRtcVO.getCodeSubprograma().longValue());
				rst = pstmt.executeQuery();
				if (rst.next()) {
					objRtcVO.setNombreSubprograma(rst.getString("NOMBRE"));
				}
			} finally {
				close(rst, pstmt);
			}
		}

		return objRtcVO;
	}

	/**
	 * HACK.. Metodo que retorna un Object[] que contiene los strings y
	 * parametros a concatenar en la consulta del metodo
	 * findBeneficiosBeneficiariosComuna.
	 * 
	 * @param filtros
	 * @return Array de Object, primer posicion String a concatenar (ej:
	 *         "AND ben.FECHA_NACIMIENTO >= TO_DATE('01/01/2000')", segunda
	 *         posicion List parametros query, tercera posicion string a
	 *         concatenar subquery, cuarta posicion List parametros subquery.
	 */
	private Object[] buildQueryFiltros(Collection<CondicionConsultaVO> filtros) {
		List<CondicionConsultaVO> lFiltros = (List<CondicionConsultaVO>) filtros;
		CondicionConsultaVO filtro = null;
		Object[] ret = new Object[4];
		StringBuffer query = new StringBuffer();
		StringBuffer sbQuery = new StringBuffer();
		List<Object> queryParams = new ArrayList<Object>();
		List<Object> sbQueryParams = new ArrayList<Object>();

		if ((Object) filtros != null) {
			for (int i = 0; i < lFiltros.size(); i++) {
				filtro = (CondicionConsultaVO) lFiltros.get(i);
				String operador = filtro.getCodFiltro();
				String tipoDato = filtro.getTipoCampo();

				query.append(" AND ");
				sbQuery.append(" AND ");
				if (tipoDato.equals(FiltrosReportesUtil.TIPO_NUMERICO)) {

					if (filtro.getCodcampo().equals(FiltrosReportesUtil.EDAD)) {
						String fechaIni = "";
						String fechaFin = "";
						int edad1 = Integer.parseInt(filtro.getValor());
						fechaIni = FiltrosReportesUtil
								.convertAgeToDateOfBirth(edad1);
						if (operador.equals(FiltrosReportesUtil.ENTRE)) {
							int edad2 = Integer.parseInt(filtro.getValor2());
							fechaFin = FiltrosReportesUtil
									.convertAgeToDateOfBirth(edad2);
						}
						if (operador.equals(FiltrosReportesUtil.ENTRE)) {
							// se invierte el orden de las fechas.
							query.append("ben."
									+ FiltrosReportesUtil.FECHA_NACIMIENTO
									+ " "
									+ FiltrosReportesUtil.ENTRE
									+ " TO_DATE(?, 'dd/mm/rrrr') AND TO_DATE(?, 'dd/mm/rrrr')");
							queryParams.add(fechaFin);
							queryParams.add(fechaIni);
							sbQuery.append("ben_."
									+ FiltrosReportesUtil.FECHA_NACIMIENTO
									+ " "
									+ FiltrosReportesUtil.ENTRE
									+ " TO_DATE(?, 'dd/mm/rrrr') AND TO_DATE(?, 'dd/mm/rrrr')");
							sbQueryParams.add(fechaFin);
							sbQueryParams.add(fechaIni);
						} else {// se invierten los operadores debido a que
								// ahora se comparan fechas y no edades.
							if (operador.equals(FiltrosReportesUtil.MAYOR)) {
								operador = FiltrosReportesUtil.MENOR;
							} else if (operador
									.equals(FiltrosReportesUtil.MAYOR_IGUAL)) {
								operador = FiltrosReportesUtil.MENOR_IGUAL;
							} else if (operador
									.equals(FiltrosReportesUtil.MENOR)) {
								operador = FiltrosReportesUtil.MAYOR;
							} else if (operador
									.equals(FiltrosReportesUtil.MENOR_IGUAL)) {
								operador = FiltrosReportesUtil.MAYOR_IGUAL;
							}
							query.append("ben."
									+ FiltrosReportesUtil.FECHA_NACIMIENTO
									+ " " + operador
									+ " TO_DATE(?, 'dd/mm/rrrr')");
							queryParams.add(fechaIni);
							sbQuery.append("ben_."
									+ FiltrosReportesUtil.FECHA_NACIMIENTO
									+ " " + operador
									+ " TO_DATE(?, 'dd/mm/rrrr')");
							sbQueryParams.add(fechaIni);
						}
						System.out.println("fini:" + fechaIni);
						System.out.println("ffin:" + fechaFin);
						continue;
					}

					if (operador.equals(FiltrosReportesUtil.IGUAL)
							|| operador.equals(FiltrosReportesUtil.DIFERENTE)
							|| operador.equals(FiltrosReportesUtil.MENOR_IGUAL)
							|| operador.equals(FiltrosReportesUtil.MAYOR_IGUAL)
							|| operador.equals(FiltrosReportesUtil.MENOR)
							|| operador.equals(FiltrosReportesUtil.MAYOR)) {
						query.append(" ben." + filtro.getCodcampo() + " "
								+ operador + " ? ");
						queryParams.add(filtro.getValor());
						sbQuery.append(" ben_." + filtro.getCodcampo() + " "
								+ operador + " ? ");
						sbQueryParams.add(filtro.getValor());
					} else {// BETWEEN
						query.append("ben." + filtro.getCodcampo() + " "
								+ operador + " ? AND ? ");
						queryParams.add(filtro.getValor());
						queryParams.add(filtro.getValor2());
						sbQuery.append("ben_." + filtro.getCodcampo() + " "
								+ operador + " ? AND ? ");
						sbQueryParams.add(filtro.getValor());
						sbQueryParams.add(filtro.getValor2());
					}

				} else if (tipoDato.equals(FiltrosReportesUtil.TIPO_FECHA)) {

					if (operador.equals(FiltrosReportesUtil.ENTRE)
							|| operador.equals(FiltrosReportesUtil.IGUAL)) {
						query.append("ben."
								+ filtro.getCodcampo()
								+ " "
								+ operador
								+ " TO_DATE(?, 'dd/mm/rrrr') AND TO_DATE(?,'dd/mm/rrrr')");
						queryParams.add(filtro.getValor());
						queryParams.add(filtro.getValor2());
						sbQuery.append("ben_."
								+ filtro.getCodcampo()
								+ " "
								+ operador
								+ " TO_DATE(?, 'dd/mm/rrrr') AND TO_DATE(?, 'dd/mm/rrrr')");
						sbQueryParams.add(filtro.getValor());
						sbQueryParams.add(filtro.getValor2());

					} else {
						query.append("ben." + filtro.getCodcampo() + " "
								+ operador + " TO_DATE(?, 'dd/mm/rrrr')");
						queryParams.add(filtro.getValor());
						sbQuery.append("ben_." + filtro.getCodcampo() + " "
								+ operador + " TO_DATE(?, 'dd/mm/rrrr')");
						sbQueryParams.add(filtro.getValor());
					}

				} else if (tipoDato
						.equals(FiltrosReportesUtil.TIPO_ALFANUMERICO)
						|| tipoDato.equals("L")) {
					if (operador.equals(FiltrosReportesUtil.IGUAL)
							|| operador.equals(FiltrosReportesUtil.DIFERENTE)) {
						query.append(" UPPER(ben." + filtro.getCodcampo()
								+ " ) " + operador + " ? ");
						queryParams.add(filtro.getValor().toUpperCase());
						sbQuery.append(" UPPER(ben_." + filtro.getCodcampo()
								+ " ) " + operador + " ? ");
						sbQueryParams.add(filtro.getValor().toUpperCase());
					} else if (operador.equals(FiltrosReportesUtil.PARECIDO)) {
						query.append(" UPPER(ben." + filtro.getCodcampo()
								+ " ) " + FiltrosReportesUtil.PARECIDO + " ? ");
						queryParams.add("%" + filtro.getValor().toUpperCase()
								+ "%");
						sbQuery.append(" UPPER(ben_." + filtro.getCodcampo()
								+ " ) " + FiltrosReportesUtil.PARECIDO + " ? ");
						sbQueryParams.add("%" + filtro.getValor().toUpperCase()
								+ "%");
					}
				} else {
					if (operador.equals(FiltrosReportesUtil.IGUAL)
							|| operador.equals(FiltrosReportesUtil.DIFERENTE)
							|| operador.equals(FiltrosReportesUtil.MENOR_IGUAL)
							|| operador.equals(FiltrosReportesUtil.MAYOR_IGUAL)
							|| operador.equals(FiltrosReportesUtil.MENOR)
							|| operador.equals(FiltrosReportesUtil.MAYOR)) {
						query.append(" ben." + filtro.getCodcampo() + " "
								+ operador + " ? ");
						queryParams.add(filtro.getValor());
						query.append(" ben_." + filtro.getCodcampo() + " "
								+ operador + " ? ");
						sbQueryParams.add(filtro.getValor());
					} else { // BETWEEN
						query.append("ben." + filtro.getCodcampo() + " "
								+ operador + " ? AND ? ");
						queryParams.add(filtro.getValor());
						queryParams.add(filtro.getValor2());
						sbQuery.append("ben_." + filtro.getCodcampo() + " "
								+ operador + " ? AND ? ");
						sbQueryParams.add(filtro.getValor());
						sbQueryParams.add(filtro.getValor2());

					}

				}

			}
		}
		ret[0] = query.toString();
		ret[1] = queryParams;
		ret[2] = sbQuery.toString();
		ret[3] = sbQueryParams;
		// System.out.println("retorno: " + retorno);
		return ret;
	}
}
